package org.hybridlabs.source.beautifier;

/**
* Copyright 2008 hybrid labs 
* 
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
*    http://www.apache.org/licenses/LICENSE-2.0 
*   
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*/

import java.util.List;

import static org.hybridlabs.source.beautifier.ImportBeautifierJalopyConstants.TYPE;
import static org.hybridlabs.source.beautifier.ImportBeautifierJalopyConstants.CLASS;
import static org.hybridlabs.source.beautifier.ImportBeautifierJalopyConstants.STATIC_IMPORT_STATEMENT;
import static org.hybridlabs.source.beautifier.ImportBeautifierJalopyConstants.PACKAGE_ANNOTATION;
import static org.hybridlabs.source.beautifier.ImportBeautifierJalopyConstants.IMPLEMENTS_CLAUSE;
import static org.hybridlabs.source.beautifier.ImportBeautifierJalopyConstants.EXTENDS_CLAUSE;
import static org.hybridlabs.source.beautifier.ImportBeautifierJalopyConstants.THROWS;

/**
 * The type context enable some convenient operation on a type extracted from
 * an abstract systax tree.
 * 
 * @author Karsten Klein, hybrid labs
 *
 */
public class TypeContext implements Comparable<TypeContext> {

    private int type;
    private List<String> sequence;
    
    private CharacterSequence qualifiedName = null;
    
    public TypeContext(int type, List<String> sequence) {
        this.type = type;
        this.sequence = sequence;
    }
    
    public CharacterSequence getQualifiedName() {
        if (qualifiedName == null) {
            StringBuffer sb = new StringBuffer(100);
            for (int i = 0; i < sequence.size(); i++) {
                if (sb.length() > 0) {
                    sb.append('.');
                }
                sb.append(sequence.get(i));
            }
            qualifiedName = new CharacterSequence(sb);
        }
        return qualifiedName;
    }

    public int getType() {
        return type;
    }
    
    public String toString() {
        return "" + getType() + " - " + getQualifiedName();
    }
    
    public void reviseType() {
        int removeIndex = -1;
        
        if (type == STATIC_IMPORT_STATEMENT) return;
        if (type == CLASS) return;
        if (type == PACKAGE_ANNOTATION) return;
        if (type == IMPLEMENTS_CLAUSE) return;
        if (type == EXTENDS_CLAUSE) return;
        if (type == TYPE) return;
        
        for (int i = 0; i < sequence.size(); i++) {
            String pos = (String) sequence.get(i);
            
            // uses java conventions to revise type
            if (pos.matches("[A-Z].*")) {
                removeIndex = i +1;
                break;
            }
        }
        
        if (removeIndex != -1 && removeIndex < sequence.size()) {
            while(sequence.size() != removeIndex) {
                sequence.remove(removeIndex);
                qualifiedName = null;
            }
        }
    }

    public int compareTo(TypeContext other) {
        CharacterSequence qf1 = getQualifiedName();
        CharacterSequence qf2 = other.getQualifiedName();
        
        // FIXME it is unclear why we need this. Normally the
        //  replacement patterns should have covered this.
        
        // changes the order of types that start with the same prefix
        if (qf2.startsWith(qf1)) {
            return -(qf1.compareTo(qf2));
        }
        
        return qf1.compareTo(qf2);
    }

    public boolean isValidType() {
        if (getType() == CLASS) return true;
        if (getType() == PACKAGE_ANNOTATION) return true;
        if (getType() == TYPE) return true;
        if (getType() == IMPLEMENTS_CLAUSE) return true;
        if (getType() == EXTENDS_CLAUSE) return true;
        if (getType() == THROWS) return true;
        
        CharacterSequence type = getQualifiedName();
        int index = type.lastIndexOf('.');
        if (index != -1) {
            CharSequence lastElement = type.substring(index + 1);
            if (lastElement.toString().matches("^[A-Z]{1,}[a-z0-9]{1,}.*")) {
                return true;
            }
        }
        return false;
    }

    public void addComponent(String component) {
        sequence.add(component);
        qualifiedName = null;
    }

    public int getLength() {
        return sequence.size();
    }
    
}
